Using The Shell Compiler To Customize The Communications Interface
The QUERY0, QUERY1, QUERY2, QUERY3, QUERY4, and QUERY5 Procedure commands provide an easy means to include preprogrammed dialog boxes in your Procedure Files. White Knight has the additional intelligence needed to process customized dialog boxes that can include multiple items of such types as simple Pushbuttons, Radio Controls, Icons, Checkboxes, Pictures (PICT items), Editable Text, and Static Text. If you have a good working knowledge about how dialog boxes are created using Apple's ResEdit program and how the above items function according to Apple's user interface guidelines, you can use this feature to provide a customized communications interface for yourself and others.
The items in your dialog box can be divided into several functional categories:
• Non-selectable and non-returning display items: These items, like Static Text, Editable Text, and non-selectable Pictures (PICT items) and Icons are used either to convey or gather information from the user while the dialog box is active. A user mouse action in an item of this type is ignored.
• Selectable but non-returning items: These items, which consist of Radio Controls and Checkboxes, are used to display current settings, and allow the user to change them while the dialog box is active. You can have up to 20 checkboxes in your dialog box, and up to 20 groups of radio controls (with an unlimited number of radio controls in each group). The tracking of these items (checking or unchecking of checkboxes and selection of a radio control and deselection of all other radio controls in the same group) is done automatically by White Knight.
• Selectable returning items: These items, pushbuttons or a special entity called a special pushbutton (discussed later) are used to close down the dialog box and resume execution of the Procedure.
The interface between your Procedure File (which calls up the dialog box) is quite simple. Before bringing up the dialog box, if you have any checkbox or radio control items, you can set their values using the following two Procedure commands:
SETBOX NUM_EXP1,NUM_EXP2
Description: This command sets the value of checkbox number NUM_EXP1 (which is a value between 1 and 20). NUM_EXP2 should be either zero (which means the box is not checkmarked) or one (which means the box is checkmarked).
Example:
(Set checkbox #1 to be uncheckmarked)
SETBOX 1,0
(Set checkbox #5 to be checkmarked)
SETBOX 5,1
--------------------
SETGROUP NUM_EXP1,NUM_EXP2
Description: This command is used to designate which radio control in a group is selected. NUM_EXP1 is the group number (from 1 to 20). NUM_EXP2 is the radio control number in the group that is the selected control (from 1 to the number of radio controls in the group).
Example:
(I have two groups of radio controls. Group #1 has 3 radio controls,)
(and number 2 is the selected control. Group #2 has 2 radio controls,)
(and number 1 is the selected control.)
(Set group #1 so that control #2 is the selected one)
SETGROUP 1,2
(Set group #2 so that control #1 is the selected one)
SETGROUP 2,1
--------------------
To execute the dialog box, the SHELL command is used. Until the user clicks the mouse inside a Pushbutton or Special Pushbutton item, the Procedure File is suspended. When the user does, the item number clicked on is returned in a numeric variable supplied with the SHELL command.
SHELL NUM_VAR,NUM_EXP
Description: This command is used to execute a dialog box. NUM_VAR is the numeric variable that will hold the item number of the pushbutton or special pushbutton that the user clicked on to exit the dialog. NUM_EXP is the resource ID numbers of the DLOG and DITL resources of the dialog box. Execution of the Procedure File is suspended until the user exits the dialog box.
Example:
(Hide the Terminal Display Window to make my display pretty)
SCREEN OFF
(Now execute the dialog box with resource ID number 1000, and return to)
(me after the user exits with the item number he clicked on the exit in)
(the numeric variable A%)
SHELL A%,1000
(A% now holds the item number of the exiting pushbutton)
--------------------
Once the dialog box has been exited from, two more Procedure commands can be used to find out what changes (if any) were made to any checkboxes and radio controls.
GETBOX NUM_VAR,NUM_EXP
Description: This command is used to interrogate the status of a checkbox. NUM_VAR will hold a zero if the checkbox is not checkmarked, or a one if the checkbox is checkmarked. NUM_EXP is the checkbox number (from 1 to 20) to interrogate.
Example:
(Find out if checkbox number 15 is checkmarked)
GETBOX A%,15
TEST A% = 1
(Ring the bell if it is)
IF YES BELL
--------------------
GETGROUP NUM_VAR,NUM_EXP
Description: This command is used to interrogate a group of radio controls to find out which radio control is the selected one in the group. NUM_VAR is a numeric variable that will contain the member number of the selected control in group number NUM_EXP (a number from 1 to 20).
Example:
(Tell me which radio control member is selected in group #3)
GETGROUP A%,3
(A% now holds the selected member number.
Think of a radio control as having three separate identities: its item number in the dialog, the group number it belongs to, and its member number in the group. A checkbox has only two identities: its item number in the dialog, and its checkbox number. Other items have only one identity: their item number in the dialog box.
The DLOG and DITL resources for a dialog box are created using ResEdit or some similar resource compiler. In the example below, I'll be using resource ID number 1000. In practice, to avoid the dialog boxes in White Knight's resource fork, you should use ID's with numbers from 9000 and above. The resource ID numbers for the DLOG and DITL resources must be identical. Any item that you do not want to have the dialog return from if the user clicks the mouse on it should be disabled (such as editable and static text items).
The DLOG resource should specify that the dialog is not visible and does not have a close box (no goAwayFlag). If you give the DLOG a ProcID of 0 (window with a title bar) White Knight will allow the dialog box window to be dragged around the screen by the user. The below is a sample DLOG created with ResEdit.
Since this DLOG has a resource number of 1000, I would then create the dialog item list (DITL) resource with a resource number of 1000. As you add each item to the DITL resource, click on the Enabled radio control (shown in the illustration below) only if the item is of type pushbutton, radio control, checkbox, or special pushbutton (special pushbuttons are discussed later on in this chapter - ResEdit doesn't know anything about such an animal). Click in the Disabled radio control for any other type of item. A sample item definition dialog for a DITL resource is shown below (using ResEdit).
It's important to remember all of the information you type into each item definition, especially the item number (shown in the title bar) and the item type.
Do not include CNTL resources or User items in your DITL resources.
Once you've created your DLOG and DITL resources (and any ICON or PICT resources contained in the DITL resource), how does White Knight know how to handle the user's interaction with the dialog box? It's done with a special resource type called SHEL. There is a special application on your master disk called Shell Compiler that will take a text file describing the items and create this resource for you. The compiler will first ask you to select the text file containing the item descriptions, and then to select the Procedure source code file to place the resulting SHEL resource into.
Why does the Shell Compiler want to put the SHEL resource into the source code file rather than into the resulting compiled Procedure File? You are probably going to be doing a lot more development and fine tuning on the Procedure File source code than on the SHEL (and associated) resources, so at the conclusion of a compilation, the Procedure Compiler inside of White Knight will look to see if the Procedure source code file has any resources. If it does, the Procedure Compiler copies all of those resources into the compiled Procedure File. This turns out to be the most natural and least painless development cycle.
One important note is that many text editors don't expect text files to have any resources. So if you use the "Save As..." menu choice in some editors to save a copy of a Procedure source code file, the SHEL, DLOG, and DITL resources may not be copied along with the text. If this is the case, you'll have to recompile the item list description with the Shell Compiler after the text file has been saved. The resources will also most likely be lost if you have to convert the text file into a word processor's format to edit it, and then back to text in order to compile it. That's why I suggest that you use a regular text editor (there are many shareware and public domain desk accessory text editor which will work beautifully) rather than a word processor.
Now let's describe the items description file that is submitted to the Shell Compiler to create the SHEL resource.
The first line of the file is a SHELLID command in the format:
SHELLID NUM_CON
This command tells the Shell Compiler what resource ID number to give the SHEL resource. NUM_CON contains this number, which should be the same number as you gave for the DLOG and DITL resource ID numbers.
The second line of the file is an ITEMS command in the format:
ITEMS NUM_CON
NUM_CON is the number of items you will be describing after this command.
Each item is then described with a DATA command which has the format:
DATA NUM_CON1,NUM_CON2,NUM_CON3,NUM_CON4,NUM_CON5,NUM_CON6,NUM_CON7
The DATA commands must be listed in the order that items are listed in the DITL resource. Therefore, the first DATA command after the ITEMS command must correspond to DITL item number one. Because of special pushbutton items, there may be more DATA statements than DITL items. We'll explain that in more detail later.
After the last DATA statement, the command ENDSHELL (no parameters) is used to signal the compiler to go ahead and generate the SHEL resource.
As you can see, there are seven numeric constants that must be provided with each DATA command. What these numeric constants mean is different for each type of item, as follows.
Pushbutton Item
NUM_CON1: 0 (zero)
NUM_CON2: 0 (zero)
NUM_CON3: 0 (zero)
NUM_CON4: 0 (zero)
NUM_CON5: 0 (zero)
NUM_CON6: 0 (zero)
NUM_CON7: 0 (zero)
Checkbox Item
NUM_CON1: 1
NUM_CON2: checkbox number (1 to 20)
NUM_CON3: 0 (zero)
NUM_CON4: 0 (zero)
NUM_CON5: 0 (zero)
NUM_CON6: 0 (zero)
NUM_CON7: 0 (zero)
Radio Control Item
NUM_CON1: 2
NUM_CON2: group number (1 to 20)
NUM_CON3: member number (1 to number of radio controls in its group)
NUM_CON4: 0 (zero)
NUM_CON5: 0 (zero)
NUM_CON6: 0 (zero)
NUM_CON7: 0 (zero)
Text Item (Static Or Editable)
NUM_CON1: 3
NUM_CON2: string variable number (see below)
NUM_CON3: (0 if text is not selected, 1 if selected)
NUM_CON4: 0 (zero)
NUM_CON5: 0 (zero)
NUM_CON6: 0 (zero)
NUM_CON7: 0 (zero)
Note: For NUM_CON2, A1$ is string variable number 0, B1$ is string variable #2, and so on up to Z1$, which is string variable number 25. The cycle continues with A2$ being string variable number 26 and so on. This variable is used to carry the item's text between the Procedure File and the dialog box upon entry and exit. If NUM_CON3 is non-zero, the entire string will be highlighted in the dialog box (as if the user had drug his mouse across the entire string). This should be used only with one editable text item in the dialog.
Item Containing Special Pushbutton Items
NUM_CON1: 4
NUM_CON2: 0 (zero)
NUM_CON3: 0 (zero)
NUM_CON4: 0 (zero)
NUM_CON5: 0 (zero)
NUM_CON6: 0 (zero)
NUM_CON7: 0 (zero)
Special Pushbutton Item
NUM_CON1: 5
NUM_CON2: DITL item number this item is contained in.
NUM_CON3: how item is to be tracked (0 = rectangle, 1 = 15,15 round rectangle, 2 = 12,12 round rectangle, 3 = 16,16 round rectangle, 4 = oval or circle)
NUM_CON4: top local coordinate of tracking rectangle
NUM_CON5: left local coordinate of tracking rectangle
NUM_CON6: bottom local coordinate of tracking rectangle
NUM_CON7: right local coordinate of tracking rectangle
Undefined Item
NUM_CON1: 6
NUM_CON2: 0 (zero)
NUM_CON3: 0 (zero)
NUM_CON4: 0 (zero)
NUM_CON5: 0 (zero)
NUM_CON6: 0 (zero)
NUM_CON7: 0 (zero)
An undefined item is one that you wish White Knight to ignore. For instance if you have defined a static text item in the dialog box, but don't wish to have its text changed by a string variable when the dialog is displayed (as it would if you gave it a "Text Item" type), give it an "Undefined Item" type. This also goes for such things as icons or pictures which are not selectable, and are included for the sake of appearance - not user interaction. Just remember that all of the items in your dialog must be described in a DATA statement to the SHEL compiler, so if an item doesn't seem to fit any of the other Shell Compiler types, give it the "Undefined Item" type.
An "Item Containing Special Pushbuttons" is used mainly for ICON and PICT items that you wish to define one or more areas inside (or the entire area of the item) that acts as a "Pushbutton Item". In other words, your dialog box could contain a picture of a city street, with street signs or store signs that the user clicks inside of to navigate to other parts of the "city". Or you might have an icon of a telephone that the user clicks on to automatically connect to a remote service. So, if item number 5 in your DITL resource was an icon, you would supply it with the "Item Containing Special Pushbuttons" type to the Shell Compiler.
After all of the DITL resource items have been listed in DATA statements, you then start listing DATA statements for the "pseudo-items" that we call "Special Pushbutton Item" types. It doesn't make any difference what order these are listed in. Each "Special Pushbutton" item's NUM_CON2 parameter tells White Knight which DITL item number it is contained in. When White Knight detects that the mouse has been pressed inside of an item of type "Item Containing Special Pushbutton Items", it goes through the list of Special Pushbutton Items belonging to that item to see if the mouse was clicked inside one of the "Special Pushbutton" item's tracking rectangles. If that's true, the Special Push Item is "tracked" by graphically inverting it like a normal pushbutton. If the mouse button is released inside of one of these items, the dialog box is exited, returning the item number of the Special Pushbutton Item (not the item containing the Special Pushbutton Item).
Remember that you must supply the tracking rectangle (NUM_CON4, NUM_CON5, NUM_CON6, and NUM_CON7) of a Special Pushbutton Item in the local coordinates of the dialog box window. A desk accessory such as Locator (available from CompuServe's Apple Developer Forum and many user groups) can be extremely helpful in determining these coordinates. The reason that there are three different types of round rectangles defined is that I've found that different "paint" programs use different preset values to determine the corner curvature of these rectangles.
Let's now demonstrate how all of the above muck fits together into a nice useful package. We're going to create a Procedure that sets certain parameters for a Hayes™ compatible modem. There are many more modem parameters we could play with than we will deal with here, but this should suffice for example. Specifically:
1) Should the modem echo back the characters I type?
2) Should the modem respond with verbal (words, like "CONNECT") responses or numeric (numbers, like "1")?
3) Should the modem answer the the phone? If so, after how many rings?
4) How many seconds should the modem wait after dialing for a connection before giving up?
The first step, after defining what the dialog box should do, is to look at the nature of each of the these questions, and then decide what appropriate items should be used in the dialog box to obtain the answers to our questions.
I would probably sketch out a sample dialog box like this:
Notice how I put little reminders in my sketch as to the number of each item. Later, when I create the actual dialog box using ResEdit, I'll need to create each item in the exact same order.
A table-type listing of the above sketch might look like this:
7 Static Text Modem answers incoming calls Disabled
8 Radio Control never Enabled
9 Radio Control after Enabled
10 Editable Text Disabled
11 Static Text rings Disabled
12 Static Text After dialing, wait Disabled
13 Editable Text Disabled
14 Static Text seconds for connection Disabled
After we write the Procedure source code, we'll use the above sketch and table to create the appropriate DLOG and DITL resources using ResEdit.
First, let's write the input file for the Shell Compiler that describes the above dialog box. Examining our sketch, we see that we have one Checkbox. We can have up to 20 Checkboxes in a dialog box, and therefore could call this Checkbox any number from 1 to 20. We'll call it #1.
Next, we see that we have two groups of Radio Controls, each having two members. Items #5 and #6 are members of one group, and Items #8 and #9 are members of a different group. Remember that we can have up to 20 groups of Radio Controls in our dialog box, and an unlimited number of members per group. We'll call the group containing Items #5 and #6 Group #1, and the group containing Items #8 and #9 Group #2. Remember that we'll also have to refer to the member number in each group, so we'll do the following:
Item #5 = Group #1, Member #1
Item #6 = Group #1, Member #2
Item #8 = Group #2, Member #1
Item #9 = Group #2, Member #2
The only other two items we'll need to keep track of are the Editable Text items. All we have to do here is assign a string variable that contains the string to be displayed in the Editable Text items when this dialog box is executed. Additionally, if the user modifies either Editable Text item, we can just look at the appropriate string variables after the dialog box is returned from to get their new contents. Note that we could have Static Text items whose contents are likewise changed upon entry to that of a string variable (of course, being static, the user could not modify them), but that wouldn't serve any purpose in our example, so we'll just call our Static Text items "undefined items" so that they'll be displayed, but ignored.
We'll link Editable Text item #10 to the A$ string variable, and item # 13 to the B$ string variable. Only one editable text item in a dialog box should have it's text selected (shown inverted), so we'll choose the topmost, item #10 for this.
(Our DLOG & DITL resources for the dialog box will have resource ID's)
(of 1000)
SHELLID 1000
(I'm about to describe the 14 items in the dialog box in order)
ITEMS 14
(Note that the below DATA statements DO NOT contain the item number in)
(the dialog box for each item. That is determined by the ORDER of each)
(DATA statement!)
(Items #1 and #2 are simple Pushbutton items)
DATA 0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0
(Item #3 is a Checkbox item, we call it Checkbox #1)
DATA 1,1,0,0,0,0,0
(Item #4 is an undefined item as far as White Knight is concerned)
DATA 6,0,0,0,0,0,0
(Item #5 is in Radio Control Group #1, and is member #1)
DATA 2,1,1,0,0,0,0
(Item #6 is in Radio Control Group #1, and is member #2)
DATA 2,1,2,0,0,0,0
(Item #7 is also Static Text we're leaving as undefined)
DATA 6,0,0,0,0,0,0
(Item #8 is in Radio Control Group #2, and is member #1)
DATA 2,2,1,0,0,0,0
(Item #9 is in Radio Control Group #2, and is member #2)
DATA 2,2,2,0,0,0,0
(Item #10 is Editable Text we'll link to the A$ string variable, and)
(show with its entry text selected)
DATA 3,0,1,0,0,0,0
(Item #11 and #12 are both undefined Static Text items)
DATA 6,0,0,0,0,0,0
DATA 6,0,0,0,0,0,0
(Item #13 is Editable Text linked to the B$ string variable, and does)
(not have its text selected)
DATA 3,1,0,0,0,0,0
(Item #14 is undefined)
DATA 6,0,0,0,0,0,0
(The following command MUST be here to tell the Shell Compiler to stop)
ENDSHELL
Before we can run the above input file through the Shell Compiler, we need a Procedure source code file to direct the output (the SHEL resource created by the Shell Compiler). The following Procedure should be typed into a text file, saved, but not yet compiled with White Knight.
(Shell Demo Program, By Scott Watson)
(First, we need to set up some defaults for our dialog box to show)
(upon entry. Select the checkbox, and member #1 of both Radio Control)
(groups. Set the first editable text item to "1" and the second)
(to "30")
SETBOX 1,1
SETGROUP 1,1
SETGROUP 2,1
COPYINTO A$,1
COPYINTO B$,30
(That's all there is to it, let's run our dialog box with the resource)
(ID of 1000, and return the item number the user clicked on to exit in)
(the A% variable)
SCREEN OFF
(Now you know why there's a SCREEN command!)
SHELL A%,1000
(If the user clicked on the Cancel button (Item #2) just get outta town)
SCREEN ON
TEST A% = 2
IF YES END
(If we got here, we know he exited with the "OK" button, so go ahead)
(and build the modem command string in Z$ based on the user's input.)
COPYINTO Z$,AT
GETBOX A%,1
(Find out if Checkbox was checked)
TEST A% = 1
IF YES CONCAT Z$,E1
IF NO CONCAT Z$,E0
(Find out which member of Radio Control Group #1 was selected)
GETGROUP A%,1
TEST A% = 1
IF YES CONCAT Z$,V1
IF NO CONCAT Z$,V0
CONCAT Z$,S0=
(Find out which member of Radio Control Group #2 was selected)
STRINGTONUM A$,B%
TEST B% > 255
IF YES LET EQUAL B%,255
GETGROUP A%,2
TEST A% = 1
IF YES CONCAT Z$,0
(This is a fancy way of validating his input. If he typed anything but)
(a valid number into the Editable Text item, the follow two lines will)
(make it zero.)
IF NO NUMTOSTRING B%,A$
IF NO CONCAT Z$,A$
(While we're at it, we'll validate his second Editable Text item too.)
(However, since zero is not a valid number, we'll need to check and)
(adjust for that.)
CONCAT Z$,S7=
STRINGTONUM B$,B%
TEST B% = 0
IF YES LET EQUAL B%,1
TEST B% > 255
IF YES LET EQUAL B%,255
NUMTOSTRING B%,B$
CONCAT Z$,B$
(Wowee! Now we should have a full modem command string. Let's type)
(a couple of AT's to make sure the modem is ready, and then spit)
(out our command string)
TYPE AT^M
PAUSE 120
TYPE AT^M
PAUSE 120
TYPE Z$
TYPE ^M
END
Now, use the sketch and descriptive table we put together earlier to create a DLOG and DITL resource each having an ID# of 1000 in the Procedure Source code file.
Finally, run the Shell Compiler, select the input file we created above, and then select the Procedure source code file to direct the output to. After the Shell Compiler is finished, you can then run White Knight, and then compile the Procedure source code to executable form.
For your convenience, the input for the Shell Compiler is provided in the file "Shell Demo.inp", and the Procedure source code (containing the DITL, DLOG, and SHEL resources) is in the file "Shell Demo.src". The compiled Procedure is in "Shell Demo.PROC".